# coding: utf-8
import platform
from enum import Enum
from pathlib import Path
from subprocess import Popen, PIPE
from typing import Union, Any, List

from common import second_time, FileEngine, logger


def get_custom_file(folder: Union[Path, str], fileType: Union[str, Enum] = 'yml'):
    """
    获取自定义文件路径
    This function returns the path of the custom file of the given type.
    :param folder: 自定义文件所在文件夹
    :param fileType: 自定义文件类型
    :return: 自定义文件路径
    """
    if isinstance(fileType, Enum):
        fileType = fileType.value
    if isinstance(folder, str):
        folder = Path(folder)
    logger.info(f'正在获取 {folder} 目录下 {fileType} 文件...')
    files = list(folder.glob(f'**/*.{fileType}'))
    files.sort()
    logger.info(f'搜索到 {len(files)} 个 {fileType} 文件')
    logger.debug(f'搜索到的 {fileType} 文件：{files}')
    return files


def set_class_attr(
        obj: object,
        files: Union[Union[Path, str], List[Union[Path, str]]],
        value: Any,
        stem: str = 'test_'
):
    """
    设置类的属性值
    :param obj: class 对象
    :param files: 自定义文件路径
    :param value: class 属性实现
    :param stem:  类属性前缀
    :return:
    """
    # 动态添加测试用例及属性
    if isinstance(files, (Path, str)):
        files = [files]
    for file in files:
        logger.info(f'正在创建 {file} 测试用例...')
        func_name = stem + file.stem
        # 防止函数名重复
        if hasattr(obj, func_name):
            logger.debug(f'测试用例 {func_name} 已存在，正在重新创建...')
            func_name = 'test_' + file.stem + '_' + second_time
            logger.debug(f'测试用例 {func_name} 重新创建成功')
        # 动态添加测试用例到类中
        logger.debug(f'创建测试用例 {func_name}...')
        setattr(obj, func_name, value(file, func_name))


def get_run_case(fileName: Union[Path, str]):
    """
    获取运行用例
    :return:
    """
    case_datas = FileEngine(fileName).read()
    case = []
    # 筛选出需要运行的用例
    for data in case_datas:
        if data.get('是否运行'):
            case.append(data)
    if not case:
        logger.warning(f'没有找到需要运行的用例，请检查 {fileName} 文件是否有配置正确的用例')
    return case


def case_main(
        obj: object,
        folder: Union[Path, str],
        value: Any,
        stem: str = 'test_',
        fileType: str = 'yml'
):
    """
    测试用例主函数
    :param obj: class 对象
    :param folder: 自定义文件路径
    :param value: class 属性实现
    :param stem:  类属性前缀
    :param fileType: 自定义文件类型
    :return:
    """
    files = get_custom_file(folder, fileType)
    set_class_attr(obj, files, value, stem)


def process_decode(cmd: Union[str, List[str]]):
    """
    Decode the output of subprocess.Popen object.
    :param cmd:
    :return:
    """
    process = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
    output, unused_err = process.communicate()
    if platform.system() == 'Windows':
        decoded_stdout = output.decode('gbk')
        decoded_err = unused_err.decode('gbk')
    else:
        decoded_stdout = output.decode('utf-8')
        decoded_err = unused_err.decode('utf-8')
    logger.info(f'命令输出：{decoded_stdout}')
    if decoded_err:
        logger.error(f'命令错误输出：{decoded_err}')
    return process
